package atomicPlayground;

import static mathUtils.VecMath.*;
import static processing.core.PConstants.ALT;
import static processing.core.PConstants.CODED;
import static processing.core.PConstants.LEFT;
import integration.IntegrableSystem;
import userInterface.Clickable;
import viscosity.Viscosity;
import drawing.Drawable;
import elec.ElectricForce;
import java.util.*;

public class AtomicParticleSystem extends IntegrableSystem implements
		Drawable, Clickable {

	AtomicPlaygroundApplet parent;
	
	ArrayList<Electron> electronList;
	ArrayList<ProtonLump> protonLumpList; 
	ArrayList<Clickable> clickList;
	ArrayList<Drawable> drawList;
	
	public ElectricForce elec;
	public Viscosity visc;
	
	public boolean showCharges = true;
	public boolean showNetCharges = true;
	
	Clickable objectGrabbed = null;
	
	public AtomicParticleSystem(AtomicPlaygroundApplet p) {this(p, 1f, 0.1f);}
	public AtomicParticleSystem(AtomicPlaygroundApplet p, float k, float c) {
		parent = p;
		elec = new ElectricForce(k);
		visc = new Viscosity(c);
		clickList = new ArrayList<Clickable>();
		drawList = new ArrayList<Drawable>();
		electronList = new ArrayList<Electron>();
		protonLumpList = new ArrayList<ProtonLump>();
	}

	public void addElectron(Electron a) {
		a.wiggle(0.1f);
		float d = 0f;
		boolean cool = false;
		while (cool==false) {
			cool = true;
			for (Electron e: electronList) {
				if (vecDist2(e.position(), a.position())<1.0f) cool = false;
			}
			if (cool==false) {
				d += 0.25f;
				a.wiggle(d);
			}
		}
		addIntegrable(a);
		elec.objectList.add(a);
		visc.objectList.add(a);
		drawList.add(a);
		electronList.add(a);
	}
	
	public void addElectron(float x, float y) {
		Electron e = new Electron(parent, x, y);
		addElectron(e);
	}
	
	public void removeElectron(float x, float y) {
		if (electronList.size()>0) {
			float loc[] = new float[2];
			loc[0] = x; loc[1] = y;
			Electron e = electronList.get(0);
			for (Electron el : electronList) {
				if (vecDist2(el.position(), loc) < vecDist2(e.position(), loc)) e = el;
			}
			removeIntegrable(e);
			elec.objectList.remove(e);
			visc.objectList.remove(e);
			drawList.remove(e);
			electronList.remove(e);
		}
	}
	
	public void addProtonLump(ProtonLump a) {
		elec.objectList.add(0, a);
		clickList.add(0, a);
		drawList.add(0, a);
		protonLumpList.add(a);
		findSlope();
	}

	public void removeProtonLump(ProtonLump a) {
		elec.objectList.remove(a);
		clickList.remove(a);
		drawList.remove(a);
		protonLumpList.remove(a);
		findSlope();
	}
	
	public void findSlope() {
		super.findSlope();
		elec.applyForces();
		visc.applyForces();
	}
	
	public void updateNetCharges() {
		for (ProtonLump p: protonLumpList) p.netCharge = p.charge;
		for (Electron e: electronList) {
			ProtonLump containedIn = null;
			for (ProtonLump p : protonLumpList) {
				if (containedIn==null && p.containsPoint(e.position())) {
					containedIn = p;
				}
			}
			if (containedIn!=null) containedIn.netCharge += e.charge();
		}		
	}
	
	public void draw() {
		updateNetCharges();

		parent.pushMatrix();

		for (ProtonLump p : protonLumpList) {
			p.draw();
		}
		if (showCharges) {
			if (protonLumpList.size()>0) {
				for (ProtonLump p : protonLumpList) p.drawCharge();
			}
		}
		if (showNetCharges)
			if (protonLumpList.size()>0) {
				for (ProtonLump p : protonLumpList) p.drawNetCharge();
			}	
		for (Electron e : electronList) {
			e.draw();
		}
		parent.popMatrix();
	}

	public boolean containsPoint(float x, float y) {
		return false;
	}
	
	public Clickable mouseClickedIn(float x, float y) {
		Clickable retVal = null;
		for (Clickable c : clickList) {
			if (retVal == null)
				retVal = c.mouseClickedIn(x, y);
		}
		if (retVal==null && parent.keyPressed == true && parent.key == CODED 
				&& parent.keyCode == ALT) {
			if (parent.mouseButton == LEFT) {
				System.out.println("Alt-click");
			}
		}
		else if (retVal!=null) {
			for (int i = protonLumpList.size()-1; i>=0; --i)
				if (protonLumpList.get(i).charge==0)
					removeProtonLump(protonLumpList.get(i));
			findSlope();
		}
		return retVal;
	}
	
	public Clickable mousePressedIn(float x, float y) {
		Clickable retVal = null;
		for (Clickable c : clickList) {
			if (retVal == null)
				retVal = c.mousePressedIn(x, y);
		}
		if (retVal!=null) {
			objectGrabbed = retVal;
			retVal = this;
		}
		return retVal;
	}

	public void mouseDragged(float dx, float dy) {
		if (objectGrabbed!=this) {
			objectGrabbed.mouseDragged(dx, dy);
			for (ProtonLump p: protonLumpList) {
				if (p==objectGrabbed) {
					for (Electron e: electronList) {
						if (p.containsPoint(e.position())) {
							e.position()[0] += dx;
							e.position()[1] += dy;
						}
					}
				}
			}
			findSlope();
		}
	}

	public void mouseReleased() {
		objectGrabbed.mouseReleased();
		objectGrabbed = null;
	}
	
	void itemDragged(Clickable itemDragged, float dx, float dy) {
		for (ProtonLump p : protonLumpList) {
			if (itemDragged==p) {
				for (Electron e : electronList) {
					if (p.containsPoint(e.position())) {
						e.position()[0] += dx;
						e.position()[1] += dy;
					}
				}
			}
		}
	}
	
}
